#include "timethis.h"
#define __BITS__ 6

void utime(long *us){
  struct timeval now;
  unsigned long t;
  gettimeofday(&now, NULL);
  t = now.tv_sec * 1000000 + now.tv_usec;
  t = t << __BITS__;
  t = t >> __BITS__;
  *us = (*us>0)? t - (*us) : t;
}
void uprint(long *us){
  fprintf(stderr, "%20ld us\n",*us);
}
void cputime(long *us){
  clock_t now;
  now = clock();
  *us = (*us>0)? now - (*us) : now;
}
void cpuprint(long *us){
  fprintf(stderr, "%20ld ticks\n", (*us) );
  fprintf(stderr, "%20lf cs\n", (double)(*us)/(double)CLOCKS_PER_SEC );
}  
int utime_(long *us, int ll){
  utime(us);
  return 0;
}
int cputime_(long *us, int ll){
  cputime(us);
  return 0;
}
int uprint_(long *us, int ll){
  uprint(us);
  return 0;
}
int cpuprint_(long *us, int ll){
  cpuprint(us);
  return 0;
}

void ntime(tt_t *ns){
  struct timespec real;
  long temp;
  #ifdef _POSIX_CPUTIME
    struct timespec proc;
  #endif
  #ifdef _POSIX_THREAD_CPUTIME
    struct timespec thrd;
  #endif
  long seg_time;
  #ifdef _POSIX_THREAD_CPUTIME
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&thrd);
  #endif
  #ifdef _POSIX_CPUTIME
    clock_gettime(CLOCK_THREAD_CPUTIME_ID ,&proc);
  #endif
  clock_gettime  (CLOCK_REALTIME          ,&real);
  if(ns->real == 0
    #ifdef _POSIX_CPUTIME
      && ns->proc == 0
    #endif
    #ifdef _POSIX_CPUTIME
      && ns->thrd == 0
    #endif
      ){
    temp = real.tv_sec * 1000000000 + real.tv_nsec;
    ns->real = temp;
    #ifdef _POSIX_CPUTIME
      temp = proc.tv_sec * 1000000000 + proc.tv_nsec;
      ns->proc = temp;
    #endif
    #ifdef _POSIX_THREAD_CPUTIME
      temp = thrd.tv_sec * 1000000000 + thrd.tv_nsec;
      ns->thrd = temp;
    #endif
  } else {
    temp = (real.tv_sec * 1000000000 + real.tv_nsec) - ns->real;
    ns->realt += temp;
    #ifdef _POSIX_CPUTIME
      temp = (proc.tv_sec * 1000000000 + proc.tv_nsec) - ns->proc;
      ns->proct += temp;
    #endif
    #ifdef _POSIX_THREAD_CPUTIME
      temp = (thrd.tv_sec * 1000000000 + thrd.tv_nsec) - ns->thrd;
      ns->thrdt += temp;
    #endif
  }
}

void nzero(tt_t *t, int flags){
  if( t == NULL ) return;
  t->real = 0l;
  #ifdef _POSIX_CPUTIME
    t->proc = 0l;
  #endif
  #ifdef _POSIX_THREAD_CPUTIME
    t->thrd = 0l;
  #endif
  if( FULL == flags ){
    t->realt = 0l;
    #ifdef _POSIX_CPUTIME
      t->proct = 0l;
    #endif
    #ifdef _POSIX_THREAD_CPUTIME
      t->thrdt = 0l;
    #endif
  }
}

void nprint(tt_t *ns){
  fprintf(stderr, "%20li ns %20li nst\n", ns->real              , ns->realt               );
  fprintf(stderr, "%20lf us %20lf ust\n", ns->real/      1000.0f, ns->realt/      1000.0f );
  fprintf(stderr, "%20lf ms %20lf mst\n", ns->real/   1000000.0f, ns->realt/   1000000.0f );
  fprintf(stderr, "%20lf s  %20lf st\n",  ns->real/1000000000.0f, ns->realt/1000000000.0f );
  
  #ifdef _POSIX_CPUTIME
    fprintf(stderr, "%20li ns %20li nst\n", ns->proc              , ns->proct               );
    fprintf(stderr, "%20lf us %20lf ust\n", ns->proc/      1000.0f, ns->proct/      1000.0f );
    fprintf(stderr, "%20lf ms %20lf mst\n", ns->proc/   1000000.0f, ns->proct/   1000000.0f );
    fprintf(stderr, "%20lf s  %20lf st\n",  ns->proc/1000000000.0f, ns->proct/1000000000.0f );
  #endif
  
  #ifdef _POSIX_THREAD_CPUTIME
    fprintf(stderr, "%20li ns %20li nst\n", ns->thrd              , ns->thrdt               );
    fprintf(stderr, "%20lf us %20lf ust\n", ns->thrd/      1000.0f, ns->thrdt/      1000.0f );
    fprintf(stderr, "%20lf ms %20lf mst\n", ns->thrd/   1000000.0f, ns->thrdt/   1000000.0f );
    fprintf(stderr, "%20lf s  %20lf st\n",  ns->thrd/1000000000.0f, ns->thrdt/1000000000.0f );
  #endif
}

int nzero_(tt_t *t, int flags, int ll){
  nzero(t,flags);
  return 1;
}
int nprint_(tt_t *t, int ll){
  nprint(t);
  return 1;
}
int ntime_(tt_t *t, int ll){
  ntime(t);
  return 1;
}

